package entity;

import util.PinyinUtil;

import java.io.File;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

// 实体类：存储文件属性

public class FileMeta {
    private int id;
    private String name; // 文件名
    private String path; // 文件存储路径
    private boolean isDirectory;  // 文件是否为目录
    // 下面这两个属性，在 java 代码中，可以没有，因为都是根据 name 属性来的
    // 可以直接给这个类加上两个 get 方法来获取到 pinyin 和 pinyinFirst
//    private String pinyin;       // 直接在下面进行 getPinyin()
//    private String pinyinFirst;  // 直接在下面进行 getPinyinFirst()
    // size 的单位是字节，最终给界面上显示的内容，则不应该是以字节为单位，应该换算成对应的 kb,mb...
    private long size;
//    private String sizeText;     // 直接在下面进行 getSizeText()
    // lastModified 是时间戳，也是一个非常大的数字，所以直接显示在界面上也不好，所以进行格式化
    private long lastModified;  // 文件的最后修改时间
//    private String lastModifiedText;  // 直接在下面进行 getLastModifiedText

    // 获取全拼音
    public String getPinyin() {
        return PinyinUtil.get(name, true);
    }

    // 获取拼音首字母
    public String getPinyinFirst() {
        return PinyinUtil.get(name, false);
    }

    public FileMeta(String name, String path, boolean idDirectory, long size, long lastModified) {
        this.name = name;
        this.path = path;
        this.isDirectory = idDirectory;
        this.size = size;
        this.lastModified = lastModified;
    }

    public FileMeta(File f) {
        // 调用上述的构造方法
        this(f.getName(), f.getParent(), f.isDirectory(), f.length(), f.lastModified());
        // getParent() 得到的是文件名之前的路径，getPath() 得到的是整个路径（包括最后的文件名）
    }

    // 重写 equals（默认的是比较两个对象的地址，比较对象身份是否相同，此处重新写用来比较 “相等”）
    /*
    当前重写了 equals，很多 java 相关的编程规范，建议再重写一下 hashCode，因为两个对象如果 equals 为 true
    此时他们得到的 hashCode 也应该相同，但是此处的代码不写 hashCode 也行，因为当前不需要把这个 FileMeta 放进哈希表里
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) {  // 看看是不是和自己比较
            return true;
        }
        if (o == null) {  // 针对 o 为 null 的特殊处理
            return false;
        }
        if (getClass() != o.getClass()) {  // 比较类型
            return false;
        }
        FileMeta fileMeta = (FileMeta) o;  // 因为上边比较了类型，所以这里一定可以是成功转换的
        return name.equals(fileMeta.name) && path.equals(fileMeta.path)
                && isDirectory == fileMeta.isDirectory;
    }

    /**
     * 通过这个方法，把 size 的值进行合理的单位换算，变成更易读的结果
     * 单位主要有 4 个：Byte, KB, MB, GB.. 由于单个文件不太可能达到 TB 级别，所以只考虑这 4 个单位
     * 进行换算主要是看 size 的大小：
     *      如果 size < 1024，单位直接使用 KB
     *      如果 size >= 1024 并且 < 1024 * 1024，单位使用 KB
     *      假设 size = 1025，此时显得结果就是：1.001 MB
     * @return 一个更易读的文件大小值
     *
     * 关键思路：
     *      1. 比较 size 和 1024 的大小
     *      2. 如果 size < 1024，直接获取到结果；如果 size >= 1024，则 /= 1024，并且单位升级一下
     */
    public String getSizeText() {
        double curSize = size;
        String[] units = {"Byte", "KB", "MB", "GB"};
        for (int level = 0; level < units.length; level++) {
            if(curSize < 1024) {
                // 不必再继续换算了，直接使用当前 level 对应的单位即可 ，BigDecimal 使精确度提高了
                return String.format("%.2f " + units[level], new BigDecimal(curSize));
            }
            curSize /= 1024;
        }
        // for 循环完了，当单位升级到 GB 还不够，还是以 GB 为单位换算
        return String.format("%.2f GB", new BigDecimal(curSize));
    }

    public String getLastModifiedText() {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return dateFormat.format(lastModified);
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public long getSize() {
        return size;
    }

    public void setSize(long size) {
        this.size = size;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getLastModified() {
        return lastModified;
    }

    public void setLastModified(long lastModified) {
        this.lastModified = lastModified;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public boolean isDirectory() {
        return isDirectory;
    }

    public void setDirectory(boolean directory) {
        isDirectory = directory;
    }
}
